#include"Task.hpp"
#include<string>
#include<vector>
#include<unistd.h>
#include<stdlib.h>
#include<cassert>
#include<time.h>
#include<wait.h>

const int processNum = 5;
std::vector<task_t> tasks;

// 先描述
class channel{
public:
    channel(int cmdfd, pid_t slaverid, std::string processName)
    :_cmdfd(cmdfd),_slaverid(slaverid),_processName(processName)
    {}

public:
    int _cmdfd;              // 发送任务的文件描述符
    pid_t _slaverid;         // 子进程的PID
    std::string _processName;  // 子进程的名字 方便我们打印日志
};

void slaver()
{
    // read(0);
    while(true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int));
        if(n == sizeof(int))
        {
            // 执行cmdcode对应的任务列表
            std::cout<< "slaver say: get a command" <<getpid()<<" :cmdcode"<< cmdcode << std::endl;
            if(cmdcode<0 || cmdcode >= tasks.size())
                continue;
            tasks[cmdcode]();
        }
        if(n==0)
            break;
    }
}

void InitProcess(std::vector<channel> *channels)
{
    for(int i=0;i<processNum;i++)
    {
        int pipefd[2]; // 临时空间
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        pid_t id = fork();
        if(id == 0) // 子进程
        {
            close(pipefd[1]); // 要读 关闭写端
            dup2(pipefd[0],0); // 让键盘读入变成从管道中读入 之后不需要传入pipefd[0], 直接从0处读即可。 因为替换了一下
            slaver();

            exit(0);
        }

        // 父进程
        close(pipefd[0]); // 要写 关闭读端
        
        // 添加channel字段
        std::string name = "process" + std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name));
    }
}

void Debug(std::vector<channel>& channels)
{
    for(const auto &c :channels)
    {
        std::cout<<c._cmdfd <<" "<<c._slaverid<< " "<<c._processName<<std::endl;
    }
}

void Menu()
{
    std::cout<<"#################################"<<std::endl;
    std::cout<<"##########1.刷新日志  2. 加钱   #########"<<std::endl;
    std::cout<<"##########3.更新野区  4. 买装备 #########"<<std::endl;
    std::cout<<"###############0. quit ###########"<<std::endl;
}

void ctrlSlaver(std::vector<channel>& channels)
{
    int which = 0;
    // int cnt =5;
    while(true)
    {
        int select = 0;
        Menu();
        std::cout<<"Please Enter@";
        std::cin>>select;
        if(select == 0 || select >=5) break;
        // select < 5
        for(int i=0; i<1; i++) // 发100次
        {
            // 1. 选择任务
            // int cmdcode = rand() % tasks.size(); // 随机选择
            int cmdcode = select - 1; // 随机选择
            
            // 2. 选择进程
            // int processpos = rand()%channels.size();

            std::cout<< "father say:" <<" cmdcode:"<<cmdcode<< " already send to "<<channels[which]._slaverid<<" process name:"<< channels[which]._processName<< std::endl;

            // 3. 发送任务
            write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode));
            which++;
            which %= channels.size();
            sleep(1);
        }
    }
}

void quitProcess(const std::vector<channel>& channels)
{
    for(const auto c:channels)
    {
        close(c._cmdfd); // 关闭写端
    }
    for(const auto c:channels)
    {
        waitpid(c._slaverid,nullptr,0);
    }
}

int main()
{
    LoadTask(&tasks);
    srand(time(nullptr)^getpid()^1023); // 种一个随机数种子
    // 再组织
    std::vector<channel> channels;
    // 1. 初始化
    InitProcess(&channels);
    // test
    // Debug(channels);

    // 2. 开始控制子进程
    ctrlSlaver(channels);

    // 3. 清理收尾
    quitProcess(channels);
    // sleep(1000);
    return 0;
}